package com.demo.gulimall.cart.service.impl;

import com.alibaba.fastjson.JSON;
import com.demo.gulimall.cart.feign.ProductFeignService;
import com.demo.gulimall.cart.interceptor.CartInterceptor;
import com.demo.gulimall.cart.service.CartService;
import com.demo.gulimall.cart.vo.*;
import com.demo.gulimall.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * @author Chen Yuan
 * @create 2023-06-19  13:30
 */
@Slf4j
@Service
public class CartServiceImpl implements CartService {

	private static final String CART_PRE = "mall:cart:";

	@Autowired
	private StringRedisTemplate redisTemplate;

	@Autowired
	private ProductFeignService productFeignService;

	@Autowired
	private ThreadPoolExecutor threadPoolExecutor;

	@Override
	public CartItemVo addToCart(Long skuId, Integer num) {
		// 获取 Redis 操作对象
		BoundHashOperations<String, Object, Object> cartOperations = getCartRedisOperations();

		// 判断当前商品是否存在, 若存在直接增加数量
		String cartItemStr = (String)cartOperations.get(skuId.toString());
		CartItemVo cartItemVo;
		if (StringUtils.isEmpty(cartItemStr)){
			// 为空, 则缓存中无此商品
			cartItemVo = new CartItemVo();
			// 封装购物车项目, 使用异步任务
			CompletableFuture<Void> skuInfoFuture = CompletableFuture.runAsync(() -> {
				R<SkuInfoVo> skuInfoRes = productFeignService.skuInfo(skuId);
				SkuInfoVo skuInfo = skuInfoRes.getData();
				cartItemVo.setCheck(true)
						.setCount(num)
						.setImage(skuInfo.getSkuDefaultImg())
						.setTitle(skuInfo.getSkuTitle())
						.setPrice(skuInfo.getPrice())
						.setSkuId(skuId);
			}, threadPoolExecutor);

			CompletableFuture<Void> skuAttrFuture = CompletableFuture.runAsync(() -> {
				R<List<String>> attrValuesRes = productFeignService.getSkuSaleAttrValuesBySkuId(skuId);
				List<String> attrValues = attrValuesRes.getData();
				cartItemVo.setSkuAttrs(attrValues);
			}, threadPoolExecutor);

			try {
				CompletableFuture.allOf(skuInfoFuture, skuAttrFuture).get();
			} catch (Exception e) {
				log.error("addToCart - 异常 - {}", e.getMessage());
			}
		}else {
			// Redis 中有, 则直接修改数量
			cartItemVo = JSON.parseObject(cartItemStr, CartItemVo.class);
			cartItemVo.setCount(cartItemVo.getCount() + num);
		}

		// 将封装好的商品加入购物车
		cartOperations.put(skuId.toString(), JSON.toJSONString(cartItemVo));
		return cartItemVo;
	}

	@Override
	public CartItemVo getCartItemVo(Long skuId) {
		// 获取 Redis 操作对象
		BoundHashOperations<String, Object, Object> cartOperations = getCartRedisOperations();
		// 判断当前商品是否存在, 若存在直接增加数量
		String cartItemStr = (String)cartOperations.get(skuId.toString());
		return JSON.parseObject(cartItemStr, CartItemVo.class);
	}

	@Override
	public CartVo getCartList(Long userId) {
		CartVo cartVo = new CartVo();
		// 判断是否登录
		UserInfoVo userInfoVo = CartInterceptor.threadLocal.get();
		userInfoVo.setUserId(userId);

		// 不论有没有登录, 都使用 Key 获取一次购物车信息
		String tempCartKey = CART_PRE + userInfoVo.getUserKey();
		List<CartItemVo> cartItemVos = getTotalCartItemList(tempCartKey);

		if (userInfoVo.getUserId() != null){
			// 已登录, 且临时购物车中有数据, 则将临时购物车更新进用户购物车
			if (null != cartItemVos && cartItemVos.size() > 0) {
				for (CartItemVo cartItemVo : cartItemVos) {
					this.addToCart(cartItemVo.getSkuId(), cartItemVo.getCount());
				}
			}

			// 临时购物车合并后, 使用 ID 获取购物车数据
			String cartKey = CART_PRE + userInfoVo.getUserId();
			cartItemVos = getTotalCartItemList(cartKey);
			// 清空临时购物车
			this.clearCart(tempCartKey);
		}

		cartVo.setCartItems(cartItemVos);
		return cartVo;
	}

	@Override
	public void clearCart(String cartKey) {
		redisTemplate.delete(cartKey);
	}

	@Override
	public void deleteCartItem(Long skuId) {
		BoundHashOperations<String, Object, Object> redisOperations = this.getCartRedisOperations();
		redisOperations.delete(skuId);
	}

	// 查询购物车中所有选中的购物项
	@Override
	public List<CartItemVo> getCheckedCartItemsByUserId(Long userId) {
		if (userId == null) {
			return null;
		}

		String cartKey = CART_PRE + userId;
		List<CartItemVo> cartItemVos = getTotalCartItemList(cartKey);
		return cartItemVos.stream().filter(CartItemVo::getCheck)
				.peek(item -> {
					// 获取商品最新的价格
					R<BigDecimal> price = productFeignService.getSkuPriceById(item.getSkuId());
					item.setPrice(price.getData());
				})
				.collect(Collectors.toList());
	}


//============================================

	private List<CartItemVo> getTotalCartItemList(String cartKey) {
		List<CartItemVo> cartItemVos = new ArrayList<>();
		BoundHashOperations<String, Object, Object> cartOperations;
		cartOperations = redisTemplate.boundHashOps(cartKey);
		List<Object> cartItemList = cartOperations.values();

		if (null != cartItemList && cartItemList.size() > 0) {
			cartItemVos = cartItemList.stream().map(item -> JSON.parseObject(String.valueOf(item), CartItemVo.class)).collect(Collectors.toList());
		}
		return cartItemVos;
	}


	private BoundHashOperations<String, Object, Object> getCartRedisOperations() {
		// 判断是否登录
		UserInfoVo userInfoVo = CartInterceptor.threadLocal.get();
		String cartKey = "";
		BoundHashOperations<String, Object, Object> cartOperations;
		if (userInfoVo.getUserId() != null){
			// 已登录
			cartKey = CART_PRE + userInfoVo.getUserId();
			cartOperations = redisTemplate.boundHashOps(cartKey);
		}else {
			// 临时用户
			cartKey = CART_PRE + userInfoVo.getUserKey();
			cartOperations = redisTemplate.boundHashOps(cartKey);
			// 设置过期时间
			cartOperations.expire(3, TimeUnit.DAYS);
		}
		// 判断当前商品是否已经加入购物车
		return cartOperations;
	}
}
